package com.appspot.mercadobgbr.client;

import com.appspot.mercadobgbr.client.ControlBar.Controls;
import com.appspot.mercadobgbr.client.MercadoBGBR.Controller;
import com.appspot.mercadobgbr.shared.BoardGame;
import com.appspot.mercadobgbr.shared.Email;
import com.appspot.mercadobgbr.shared.Usuario;
import com.google.gwt.dom.client.ButtonElement;
import com.google.gwt.dom.client.DivElement;
import com.google.gwt.dom.client.Document;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.ImageElement;
import com.google.gwt.dom.client.InputElement;
import com.google.gwt.dom.client.LabelElement;
import com.google.gwt.dom.client.OptionElement;
import com.google.gwt.dom.client.SelectElement;
import com.google.gwt.dom.client.Style.Display;
import com.google.gwt.dom.client.Style.Position;
import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.dom.client.Style.Visibility;
import com.google.gwt.resources.client.CssResource;
import com.google.gwt.resources.client.ImageResource;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.EventListener;

public class JogoDetails extends Page {

	public interface Css extends CssResource {
		String back();

		String field();

		String fieldGroup();

		String label();

		String jogoDetails();

		String procura();
	}

	public interface Resources extends ControlBar.Resources {
		@Source("resources/back.png")
		ImageResource back();

		@Source("resources/JogoDetails.css")
		JogoDetails.Css jogoDetailsCss();
	}

	public static Controls createControls(final Controller controller,
			JogoDetails.Resources resources) {
		JogoDetails.Css css = resources.jogoDetailsCss();

		Controls controls = new Controls(resources);
		controls.addControl(css.back(), new EventListener() {
			public void onBrowserEvent(Event event) {
				controller.goToJogoList();
			}
		});

		return controls;
	}

	private final Controller controller;
	private BoardGame currentJogo;
	private final JogoDetails.Resources resources;
	private final ButtonElement procuraButton;
	private final ButtonElement incluiButton;
	private final ButtonElement vendiButton;
	public final ButtonElement emailButton;
	private final InputElement codigoField;
	private final InputElement nomeField;
	private final InputElement valorField;
	private final InputElement observacaoField;
	private final InputElement emailField;
	private final SelectElement boardSelect;
	private final SelectElement freteSelect;
	private final DivElement boardSelectDiv;
	private final ImageElement imagemBoard;
	private final DivElement emailDiv;
	private final InputElement negociarCheck;
	private final InputElement localField;

	protected JogoDetails(PageTransitionPanel parent, Controls controls, Controller controller,
			JogoDetails.Resources resources) {
		super(parent, controls, resources);
		this.resources = resources;
		this.controller = controller;
		Element contentElem = getContentContainer();
		contentElem.setClassName(resources.jogoDetailsCss().jogoDetails());
		Document doc = Document.get();

		codigoField = doc.createHiddenInputElement().cast();

		nomeField = doc.createElement("input").cast();
		DivElement nomeDiv = contentElem.appendChild(createLabelledFieldGroup("Jogo:", nomeField));

		procuraButton = doc.createPushButtonElement();
		procuraButton.setInnerText("Procurar");
		procuraButton.setClassName(resources.jogoDetailsCss().procura());
		nomeDiv.appendChild(procuraButton);

		boardSelect = doc.createSelectElement().cast();
		boardSelect.getStyle().setVisibility(Visibility.HIDDEN);
		boardSelectDiv = contentElem.appendChild(createLabelledFieldGroup("", boardSelect));

		imagemBoard = doc.createImageElement().cast();
		contentElem.appendChild(createLabelledFieldGroup("", imagemBoard));

		valorField = doc.createElement("input").cast();
		valorField.getStyle().setWidth(100, Unit.PX);
		DivElement valorDiv = contentElem.appendChild(createLabelledFieldGroup("Valor: R$",
				valorField));
		negociarCheck = doc.createCheckInputElement();
		negociarCheck.setTitle("Valor à combinar");
		negociarCheck.getStyle().setWidth(20, Unit.PX);
		negociarCheck.getStyle().setLeft(227, Unit.PX);
		negociarCheck.getStyle().setPosition(Position.ABSOLUTE);
		negociarCheck.setId("negociarCheck");
		valorDiv.appendChild(negociarCheck);
		LabelElement negociarText = doc.createLabelElement();
		negociarText.setInnerText("Valor à combinar");
		negociarText.getStyle().setPosition(Position.RELATIVE);
		negociarText.getStyle().setDisplay(Display.INLINE);
		negociarText.getStyle().setLeft(155, Unit.PX);
		negociarText.setHtmlFor("negociarCheck");
		valorDiv.appendChild(negociarText);

		freteSelect = doc.createSelectElement().cast();
		criarOpcoesFrete();
		contentElem.appendChild(createLabelledFieldGroup("Frete:", freteSelect));

		localField = doc.createElement("input").cast();
		localField.setDisabled(true);
		contentElem.appendChild(createLabelledFieldGroup("Local:", localField));

		observacaoField = doc.createTextAreaElement().cast();
		contentElem.appendChild(createLabelledFieldGroup("Observações: (condições do jogo, etc.)",
				observacaoField));

		incluiButton = doc.createPushButtonElement();
		incluiButton.setDisabled(true);
		incluiButton.setInnerText("Incluir Jogo");
		incluiButton.getStyle().setPosition(Position.ABSOLUTE);
		DivElement botoesDiv = contentElem.appendChild(createLabelledFieldGroup("", incluiButton));

		vendiButton = doc.createPushButtonElement();
		vendiButton.getStyle().setVisibility(Visibility.HIDDEN);
		vendiButton.getStyle().setPosition(Position.ABSOLUTE);
		vendiButton.getStyle().setLeft(230, Unit.PX);
		vendiButton.setInnerText("Jogo vendido!");
		botoesDiv.appendChild(vendiButton);

		emailField = doc.createTextAreaElement().cast();
		emailDiv = contentElem.appendChild(createLabelledFieldGroup(
				"Interessou? Avise o vendedor:", emailField));

		emailButton = doc.createPushButtonElement();
		emailButton.getStyle().setVisibility(Visibility.HIDDEN);
		
		contentElem.appendChild(createLabelledFieldGroup("", emailButton));

		hookEventListeners();
	}

	private void criarOpcoesFrete() {
		incluirOpcao("Frete por conta do comprador", "0", freteSelect);
		incluirOpcao("Frete incluso", "1", freteSelect);
		incluirOpcao("Não se aplica", "2", freteSelect);
	}

	private void incluirOpcao(String text, String value, SelectElement selectElement) {
		OptionElement option = Document.get().createOptionElement();
		option.setText(text);
		option.setValue(value);
		selectElement.add(option, null);
	}

	public void setBoardGames(BoardGame[] boardGames) {
		limparBoardSelect();
		boardSelect.getStyle().setVisibility(Visibility.VISIBLE);
		OptionElement option = Document.get().createOptionElement();
		if (boardGames.length > 0) {
			option.setText("[ESCOLHA UM JOGO]");
		} else {
			option.setText("NENHUM JOGO ENCONTRADO");
		}
		boardSelect.add(option, null);
		boolean achou = false;
		for (BoardGame bg : boardGames) {
			option = Document.get().createOptionElement();
			option.setText(bg.getName());
			option.setValue(bg.getCodigoBGG());
			if (nomeField.getValue().equalsIgnoreCase(bg.getName()) && !achou) {
				option.setSelected(true);
				controller.getBoardGame(bg);
				achou = true;
			}
			boardSelect.add(option, null);
		}
	}

	private void limparBoardSelect() {
		for (int i = boardSelect.getChildCount(); i >= 0; i--) {
			boardSelect.remove(i);
		}
		boardSelect.getStyle().setVisibility(Visibility.HIDDEN);
	}

	public void setBoardGame(BoardGame boardGame) {
		currentJogo = boardGame;
		mostraJogo(false, currentJogo.getThumb());
		codigoField.setValue(currentJogo.getCodigoBGG());
		nomeField.setValue(currentJogo.getName());
	}

	private void mostraJogo(boolean esconde, String thumb) {
		incluiButton.setDisabled(esconde);
		imagemBoard.setSrc(thumb);
		if (esconde) {
			imagemBoard.getStyle().setVisibility(Visibility.HIDDEN);
		} else {
			imagemBoard.getStyle().setVisibility(Visibility.VISIBLE);
		}
	}

	public void setFocus() {
		nomeField.focus();
	}

	public void view(BoardGame data) {
		currentJogo = data;
		limparBoardSelect();
		if (data != null) {
			populateFields();
		} else {
			resetFields();
		}
	}

	private DivElement createLabelledFieldGroup(String labelText, Element field) {
		DivElement fieldGroup = Document.get().createDivElement();
		fieldGroup.setClassName(resources.jogoDetailsCss().fieldGroup());

		DivElement label = Document.get().createDivElement();
		label.setInnerText(labelText);

		label.setClassName(resources.jogoDetailsCss().label());
		field.setClassName(resources.jogoDetailsCss().field());

		fieldGroup.appendChild(label);
		fieldGroup.appendChild(field);

		return fieldGroup;
	}

	private void hookEventListeners() {

		DomUtils.addEventListener("click", procuraButton, new EventListener() {
			public void onBrowserEvent(Event event) {
				mostraJogo(true, null);
				boardSelect.getStyle().setVisibility(Visibility.HIDDEN);
				currentJogo = new BoardGame(null);
				currentJogo.setName(nomeField.getValue());
				if (!validateFields(currentJogo)) {
					currentJogo = null;
					mostraJogo(true, null);
				}
			}
		});

		DomUtils.addEventListener("click", negociarCheck, new EventListener() {
			public void onBrowserEvent(Event event) {
				if (negociarCheck.isChecked()) {
					valorField.setDisabled(true);
					valorField.setValue("Valor à combinar");
				} else {
					valorField.setDisabled(false);
					valorField.setValue("");
				}
			}
		});

		DomUtils.addEventListener("click", incluiButton, new EventListener() {
			public void onBrowserEvent(Event event) {
				boolean semErro = true;
				try {
					currentJogo.setNegociarValor(negociarCheck.isChecked());
					if (negociarCheck.isChecked() || valorField.getValue().equals("")) {
						currentJogo.setValor(0);
					} else {
						String valor = valorField.getValue();
						valor = valor.replace(',', '.');
						currentJogo.setValor(Double.parseDouble(valor));
					}
				} catch (Exception e) {
					DomUtils.getWindow().alert(
							"Valor inválido! Deve ser numérico ou deixado em branco.");
					semErro = false;
				}
				if (semErro) {
					currentJogo.setCodigoBGG(codigoField.getValue());
					currentJogo.setName(nomeField.getValue());
					currentJogo.setFrete(freteSelect.getValue());
					currentJogo.setObservacao(observacaoField.getValue());
					currentJogo.setEmail(controller.getEmailUsuario());
					currentJogo.setVendedor(controller.getUsuario());
					if (currentJogo.getId() == null) {
						controller.addNewJogo(currentJogo);
					} else {
						controller.updateJogo(currentJogo);
					}
				}
			}
		});

		DomUtils.addEventListener("click", vendiButton, new EventListener() {
			public void onBrowserEvent(Event event) {
				if (DomUtils.getWindow().confirm("Confirma a venda deste jogo?")) {
					controller.venderJogo(currentJogo);
				}
			}
		});

		DomUtils.addEventListener("click", emailButton, new EventListener() {
			public void onBrowserEvent(Event event) {
				if (emailField.getValue().trim().equals("")) {
					DomUtils.getWindow().alert("E-mail para o vendedor não pode ser em branco.");
				} else {
					Email email = new Email(emailField.getValue(), currentJogo, controller
							.getEmailUsuario(), controller.getNicknameUsuario());
					emailButton.setDisabled(true);
					emailButton.setInnerText("Enviando e-mail...");
					controller.enviarEmail(email);
				}
			}
		});

		DomUtils.addEventListener("change", boardSelect, new EventListener() {
			public void onBrowserEvent(Event event) {
				mostraJogo(true, null);
				controller.getBoardGame(new BoardGame(boardSelect.getOptions()
						.getItem(boardSelect.getSelectedIndex()).getValue()));
			}
		});

		/*
		 * DomUtils.addEventListener("click", nomeField, new EventListener() {
		 * public void onBrowserEvent(Event event) { codigoField.setValue(""); }
		 * });
		 */
	}

	private void populateFields() {
		procuraButton.getStyle().setVisibility(Visibility.HIDDEN);
		codigoField.setValue(currentJogo.getCodigoBGG());

		nomeField.setValue(currentJogo.getName());
		nomeField.setDisabled(true);
		mostraJogo(false, currentJogo.getThumb());
		valorField.setValue(String.valueOf(currentJogo.getValor()));
		observacaoField.setValue(currentJogo.getObservacao());
		incluiButton.setInnerText("Salvar Alterações");

		boolean naoDono = !currentJogo.getEmail().equals(controller.getEmailUsuario());
		observacaoField.setDisabled(naoDono);

		if (naoDono) {
			valorField.setDisabled(true);
			incluiButton.getStyle().setVisibility(Visibility.HIDDEN);
			vendiButton.getStyle().setVisibility(Visibility.HIDDEN);
			emailDiv.getStyle().setVisibility(Visibility.VISIBLE);
			emailField.setValue("Oi, gostei do seu jogo. Quero comprar!");
			emailButton.getStyle().setVisibility(Visibility.VISIBLE);
			emailField.setDisabled(currentJogo.isEnviado());
			emailButton.setDisabled(currentJogo.isEnviado());
			if (currentJogo.isEnviado()) {
				emailButton.setInnerText("Enviar e-mail");
			} else {
				emailButton.setInnerText("E-mail enviado");
			}
			negociarCheck.getStyle().setVisibility(Visibility.HIDDEN);
		} else {
			valorField.setDisabled(currentJogo.isNegociarValor());
			incluiButton.getStyle().setVisibility(Visibility.VISIBLE);
			vendiButton.getStyle().setVisibility(Visibility.VISIBLE);
			emailDiv.getStyle().setVisibility(Visibility.HIDDEN);
			emailButton.getStyle().setVisibility(Visibility.HIDDEN);
			negociarCheck.getStyle().setVisibility(Visibility.VISIBLE);
		}
		
		freteSelect.setDisabled(naoDono);
		
		negociarCheck.setChecked(currentJogo.isNegociarValor());

		boardSelectDiv.getStyle().setPosition(Position.ABSOLUTE);

		localField.setValue(currentJogo.getVendedor().getLocal());
		
		freteSelect.setSelectedIndex(Integer.valueOf(currentJogo.getFrete()));
	}

	private void resetFields() {
		procuraButton.getStyle().setVisibility(Visibility.VISIBLE);
		codigoField.setValue("");

		nomeField.setValue("");
		nomeField.setDisabled(false);
		mostraJogo(true, null);
		valorField.setValue("");
		observacaoField.setValue("");
		incluiButton.setInnerText("Incluir Jogo");

		valorField.setDisabled(false);
		observacaoField.setDisabled(false);

		incluiButton.getStyle().setVisibility(Visibility.VISIBLE);
		vendiButton.getStyle().setVisibility(Visibility.HIDDEN);

		emailDiv.getStyle().setVisibility(Visibility.HIDDEN);
		emailButton.getStyle().setVisibility(Visibility.HIDDEN);

		boardSelectDiv.getStyle().setPosition(Position.RELATIVE);

		localField.setValue(controller.getUsuario().getLocal());
		
		negociarCheck.getStyle().setVisibility(Visibility.VISIBLE);
		negociarCheck.setChecked(false);
		freteSelect.setDisabled(false);
	}

	private boolean validateFields(BoardGame potentialJogo) {
		String nome = potentialJogo.getName();
		if (nome.equals("")) {
			DomUtils.getWindow().alert("Código BGG válido - deve ser numérico.");
			return false;
		} else {
			controller.getBoardGame(potentialJogo);
			return true;
		}
	}

	private boolean numeroInvalido(String codigoBGG) {
		try {
			int i = Integer.parseInt(codigoBGG);
			return i <= 0;
		} catch (NumberFormatException nfe) {
			return true;
		}
	}

}
